//
// Created by 原帅 on 2022/10/2.
//

#include "RLogRecorder.h"
#include "dirent.h"
#include "sys/stat.h"
#include "vector"
#include "regex"
#include "iostream"
#include "sys/time.h"
#include "assert.h"

#define RLOG_DATE_SIZE 30

RLogRecorder::RLogRecorder(const std::string logName) : logName(logName) {

    this->checkLogFiles();
}

void RLogRecorder::recordlog(RLOGLEVEL rloglevel, std::string msg) {
    if (this->ofs == nullptr) {
        checkLogFiles();
    }
    if (this->ofs == nullptr) {
        assert(0);
    }

    struct timeval tv;
    gettimeofday(&tv,NULL);
    struct tm tm;
    localtime_r(&tv.tv_sec,&tm);

    char dateNow[RLOG_DATE_SIZE] = {0};
    strftime(dateNow,RLOG_DATE_SIZE,"%F %T",&tm);
    std::string str ="";
    switch (rloglevel) {
        case RLogRecorder::ERROR:
            str.append("ERROR ");
            break;
        case RLogRecorder::DEBUG:
            str.append("DEBUG ");
            break;
        default:
            str.append("USER ");
            break;
    }
    str.append(dateNow)
        .append(".")
        .append(std::to_string(tv.tv_usec))
//        .append(" ")
//        .append(__FILE__)
//        .append(":")
//        .append(to_string(__LINE__))
//        .append(":")
//        .append(__func__ )
//        .append(":")
        .append(msg);
    *ofs << str << std::endl;

    if(ofs->tellp()>=LOG_FILE_MAX_SIZE)
    {
        moveToNextLogFile();
    }
}

RLogRecorder::~RLogRecorder() {
    if (ofs) ofs->close();
}

void RLogRecorder::checkLogFiles() {
    /// log 目录检查
    std::string logDirPath = LOG_FILE_PATH;
    DIR *logdir = opendir(logDirPath.c_str());
    if (logdir == nullptr){
        int iRet = mkdir(logDirPath.c_str(),0777);
        switch (iRet) {
            case 0:
                logdir = opendir(logDirPath.c_str());
                break;
            default:
                printf("error:%s\n",strerror(errno));
                return;
        }
    }

    if (logdir == nullptr) {
        printf("error:%s\n",strerror(errno));
        assert(0);
    }

    std::string regexNname ="";
    regexNname.append(logDirPath).append("/").append(this->logName).append("\\.").append("[0-9]*\\").append(".").append(LOG_FILE_SUFFIX);
    std::regex regexStr(regexNname.c_str());

    dirent* diritem = nullptr;
    std::vector<std::string> fileNames;
    while ((diritem = readdir(logdir)) != nullptr) {
        if (strcmp(diritem->d_name,".")==0 || strcmp(diritem->d_name,"..")==0) {
            continue;
        }
        std::string dirFileName="";
        dirFileName.append(logDirPath).append("/").append(diritem->d_name);

        std::smatch matchRes;
        if (regex_match(dirFileName,matchRes,regexStr))
        {
            fileNames.push_back(dirFileName);
        }
    }

    for (; this->logCurIndex<LOG_FILE_MAX_INDEX; this->logCurIndex++) {
        std::string tempName = "";
        tempName.append(logDirPath)
                .append("/")
                .append(this->logName)
                .append(".")
                .append(std::to_string(this->logCurIndex))
                .append(".")
                .append(LOG_FILE_SUFFIX);

        if (find(fileNames.begin(),fileNames.end(),tempName) != fileNames.end()) {
            /// 找到了，判断文件大小
            struct stat fileStat ={0};
            stat(tempName.c_str(),&fileStat);
            if (fileStat.st_size>LOG_FILE_MAX_SIZE){
                /// 如果是最后一个log文件大小也超过了限制，寻找最早的一个
                if (this->logCurIndex==LOG_FILE_MAX_INDEX-1) {
                    std::string lastMFileName = "";
                    long lastMTime = 0x7fffffffffffffff;
                    for (auto mfileName:fileNames) {
                        struct stat mfileStat ={0};
                        stat(mfileName.c_str(),&mfileStat);
#ifdef __APPLE__
                        if (mfileStat.st_mtimespec.tv_sec < lastMTime) {
                            lastMTime = mfileStat.st_mtimespec.tv_sec;
                            lastMFileName.assign(mfileName);
                        }
#elif __LINUX__
                        if (mfileStat.st_mtime < lastMTime) {
                            lastMTime = mfileStat.st_mtime;
                            lastMFileName.assign(mfileName);
                        }
#endif
                    }
                    ofs= new std::ofstream(lastMFileName.c_str(),std::ios::ate);
                    std::regex lastregexStr("\\.[0-9]+\\.");
                    std::smatch lastmatchRes;
                    regex_search(lastMFileName,lastmatchRes,lastregexStr);
                    std::smatch numMatchRes;
                    std::string lastmatchstr = lastmatchRes.str();
                    std::regex numRes("[0-9]+");
                    regex_search(lastmatchstr,numMatchRes,numRes);
                    /// 这里理论上会有bug， log index 有可能是不确定的数字
                    this->logCurIndex = atoi(numMatchRes.str().c_str());
                    break;
                }
                continue;
            } else {
                ofs = new std::ofstream(tempName.c_str(),std::ios::app);
                break;
            }
        } else {
            /// 没找到
            ofs = new std::ofstream(tempName.c_str(),std::ios::ate);
            break;
        }
    }
}

void RLogRecorder::moveToNextLogFile() {
    this->logCurIndex++;
    if (this->logCurIndex>=LOG_FILE_MAX_INDEX) {
        this->logCurIndex = 0;
    }

    if (ofs){
        if (ofs->is_open())
        {
            ofs->flush();
            ofs->close();
        }
        delete ofs;
        ofs = nullptr;
    }

    std::string tempName = "";
    tempName.append(LOG_FILE_PATH)
            .append("/")
            .append(this->logName)
            .append(".")
            .append(std::to_string(this->logCurIndex))
            .append(".")
            .append(LOG_FILE_SUFFIX);
    ofs = new std::ofstream(tempName.c_str(),std::ios::ate);
}
